using System;
using System.Collections;
using System.Data;
using NUnit.Framework;

namespace PaulRz.Util
{
	/// <summary>
	/// Summary description for RussianTranscription.
	/// </summary>
	public sealed class RussianTranscription
	{
		private RussianTranscription() {}
		
		public static string Transcript(string value_in_cyrillic) 
		{
			if (value_in_cyrillic == null) 
			{
				return null;
			}
			if (transcriptionTable == null) 
			{
				transcriptionTable = new TranscriptionTable();
			}
			return transcriptionTable.Transcript(value_in_cyrillic);
		}

		public static void test()
		{
			string tran = Transcript("Nokia придумала, чем привлечь покупателей");
			Console.Out.WriteLine(tran);
			Assert.AreEqual(tran, "Nokia pridumala, chem privlech pokupateley");
		}

		public static DataTable Transcript(DataTable table_in_cyrillic) 
		{
			if (table_in_cyrillic == null) 
			{
				return null;
			}
			ArrayList string_columns = new ArrayList();
			foreach (DataColumn column in table_in_cyrillic.Columns) 
			{
				if (column.DataType == typeof(string)) 
				{
					string_columns.Add(column);
				}
			}
			foreach (DataRow row in table_in_cyrillic.Rows) 
			{
				foreach (DataColumn column in string_columns) 
				{
					if (row[column] is string) 
					{
						row[column] = Transcript((string) row[column]);
					}
				}
			}
			return table_in_cyrillic;
		}

		private class TranscriptionTable 
		{
			public TranscriptionTable() 
			{
				addSimple('а', "a");
				addSimple('б', "b");
				addSimple('в', "v");
				addSimple('г', "g");
				addSimple('д', "d");
				addSimple('е', "e");
				addSimple('ё', "yo");
				addSimple('ж', "zh");
				addSimple('з', "z");
				addSimple('и', "i");
				addSimple('й', "y");
				addSimple('к', "k");
				addSimple('л', "l");
				addSimple('м', "m");
				addSimple('н', "n");
				addSimple('о', "o");
				addSimple('п', "p");
				addSimple('р', "r");
				addSimple('с', "s");
				addSimple('т', "t");
				addSimple('у', "u");
				addSimple('ф', "f");
				addSimple('х', "kh");
				addSimple('ц', "ts");
				addSimple('ч', "ch");
				addSimple('ш', "sh");
				addSimple('щ', "sch");
				addLastEmpty('ъ', "'");
				addSimple('ы', "y");
				addLastEmpty('ь', "'");
				addSimple('э', "e");
				addSimple('ю', "yu");
				addSimple('я', "ya");

				replaceTable.Add("ks", "x");
				replaceTable.Add("kS", "X");
				replaceTable.Add("Ks", "X");
				replaceTable.Add("KS", "X");
			}
			public string Transcript(string whole_word) 
			{
				string result = string.Empty;
				int count = whole_word.Length;
				for (int i = 0; i < count; ++i) 
				{
					result += transcriptletter(whole_word, i);
				}
				foreach (string old_text in replaceTable.Keys) 
				{
					result = result.Replace(old_text, (string)replaceTable[old_text]);
				}
				return result;
			}
			Hashtable tableLetterTranscription = new Hashtable();
			Hashtable replaceTable = new Hashtable();
			private void addSimple(char cyrilic_letter, string transcription) 
			{
				add(new SimpleLetterTranscription(cyrilic_letter, transcription));
			}
			private void addLastEmpty(char cyrilic_letter, string transcription) 
			{
				add(new LastEmptyLetterTranscription(cyrilic_letter, transcription));
			}
			private void add(SimpleLetterTranscription letter_transcription) 
			{
				if (!tableLetterTranscription.Contains(letter_transcription.CyrilicLetter)) 
				{
					tableLetterTranscription.Add(letter_transcription.CyrilicLetter, letter_transcription);
				}
			}
			private string transcriptletter(string whole_word, int letter_index) 
			{
				if (whole_word.Length <= letter_index) 
				{
					return string.Empty;
				}
				char the_letter = whole_word[letter_index];
				char the_lower_letter = Char.ToLower(the_letter);
				if (tableLetterTranscription.Contains(the_lower_letter)) 
				{
					return ((SimpleLetterTranscription)tableLetterTranscription[the_lower_letter]).Process(whole_word, letter_index);
				}
				return new string(the_letter, 1);
			}

		}

		static private TranscriptionTable transcriptionTable = null;

		private class SimpleLetterTranscription
		{
			private char cyrilicLetter;
			private string transcription;
			public SimpleLetterTranscription(char cyrilic_letter, string transcription)
			{
				this.cyrilicLetter = Char.ToLower(cyrilic_letter);
				this.transcription = transcription.ToLower();
			}
			public char CyrilicLetter { get { return this.cyrilicLetter; } }

			private static void casing(
				string whole_word,
				int letter_index,
				ref bool all_capital,
				ref bool decided) 
			{
				if (decided) 
				{
					return;
				}
				if (letter_index < 0 || letter_index >= whole_word.Length) 
				{
					return;
				}
				char the_letter = whole_word[letter_index];
				if (Char.IsLower(the_letter)) 
				{
					all_capital = false;
					decided = true;
				} 
				else if (Char.IsUpper(the_letter)) 
				{
					all_capital = true;
				}
			}

			public virtual string Process(string whole_word, int letter_index) 
			{
				if (whole_word.Length <= letter_index) 
				{
					return string.Empty;
				}
				char the_letter = whole_word[letter_index];
				if (Char.ToLower(the_letter) != this.cyrilicLetter) 
				{
					return new string(the_letter, 1);
				}
				string result = this.transcription;
				if (result.Length > 0 && Char.IsUpper(the_letter)) 
				{
					bool neigbour_is_capital = false;
					bool decided = false;
					casing(whole_word, letter_index - 1, ref neigbour_is_capital, ref decided);
					casing(whole_word, letter_index + 1, ref neigbour_is_capital, ref decided);
					if (neigbour_is_capital) 
					{
						result = result.ToUpper();
					}
					else 
					{
						result = Char.ToUpper(result[0]) + result.Substring(1);
					}
				}
				return result;
			}
		}

		private class LastEmptyLetterTranscription : SimpleLetterTranscription
		{
			public LastEmptyLetterTranscription(char cyrilic_letter, string transcription)
				: base(cyrilic_letter, transcription)
			{
			}
			public override string Process(string whole_word, int letter_index) 
			{
				if (whole_word.Length <= letter_index + 1 ||
					!Char.IsLetter(whole_word[letter_index + 1]))
				{
					return string.Empty;
				}
				return base.Process(whole_word, letter_index);
			}
		}
	}
}
